// CONVENIENCE FUNCTIONS

// Event functions from http://www.quirksmode.org/js/eventSimple.html
var addEventSimple = function(el, evt, fn) {
  if (el.addEventListener) {
    el.addEventListener(evt, fn, false);
  } else if (el.attachEvent) {
    el.attachEvent('on' + evt, fn);
  }
};
// alias
var addEvent = addEventSimple;

// Add/remove/has class functions from http://snipplr.com/view/3561/addclass-removeclass-hasclass/
var hasClass = function(ele,cls) {
  return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

var addClass = function(ele,cls) {
  if (!hasClass(ele,cls)) {
    ele.className += " " + cls;
  }
}

var removeClass = function(ele,cls) {
  if (hasClass(ele,cls)) {
    var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
    ele.className = ele.className.replace(reg,' ');
  }
}

// getElementsByClass function from ddiaz
var getElementsByClass = function(searchClass,node,tag) {
  var classElements = [];
  if (!node) {
    node = document;
  }
  if (!tag) {
    tag = '*';
  }
  var els = node.getElementsByTagName(tag);
  var elsLen = els.length;
  var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
  for (i = 0, j = 0; i < elsLen; i++) {
    if (pattern.test(els[i].className)) {
      classElements[j] = els[i];
      j++;
    }
  }
  return classElements;
};

// The get parent/child/sibling element methods
var parentElement = function(node) {
  if (node.parentElement !== undefined) {
    return node.parentElement;
  }
  node = node.parentNode;
  while (node && node.nodeType != 1) {
    node = node.parentNode;
  }
  return node;
}

var childElements = function(node) {
  if (node.childElements !== undefined) {
    return node.childElements;
  }
  var elements = [];
  var childNodes = node.childNodes;
  for (var i = 0; i < childNodes.length; ++i) {
    if (childNodes[i].nodeType == 1) {
      elements.push(childNodes[i]);
    }
  }
  return elements;
}

var previousElementSibling = function(node) {
  if (node.previousElementSibling !== undefined) {
    return node.previousElementSibling;
  }
  var sibling = node.previousSibling;
  while (sibling && sibling.nodeType != 1) {
    sibling = sibling.previousSibling;
  }
  return sibling;
}

var nextElementSibling = function(node) {
  if (node.nextElementSibling !== undefined) {
    return node.nextElementSibling;
  }
  var sibling = node.nextSibling;
  while (sibling && sibling.nodeType != 1) {
    sibling = sibling.nextSibling;
  }
  return sibling;
}

var firstElementChild = function(node) {
  if (node.firstElementChild !== undefined) {
    return node.firstElementChild;
  }
  if (node.firstChild && node.firstChild.nodeType != 1) {
    return nextElementSibling(node.firstChild);
  }
  return node.firstChild;
}

var lastElementChild = function(node) {
  if (node.lastElementChild !== undefined) {
    return node.lastElementChild;
  }
  if (node.lastChild && node.lastChild.nodeType != 1) {
    return previousElementSibling(node.lastChild);
  }
  return node.lastChild;
}

var previousElementSiblingWithTagName = function(node, tag) {
  var sibling = previousElementSibling(node);
  while (sibling && sibling.nodeName.toLowerCase() != tag.toLowerCase()) {
    sibling = previousElementSibling(sibling);
  }
  return sibling;
}

var nextElementSiblingWithTagName = function(node, tag) {
  var sibling = nextElementSibling(node);
  while (sibling && sibling.nodeName.toLowerCase() != tag.toLowerCase()) {
    sibling = nextElementSibling(sibling);
  }
  return sibling;
}

var firstElementChildWithTagName = function(node, tag) {
  var child = firstElementChild(node);
  if (child && child.nodeName.toLowerCase() != tag.toLowerCase()) {
    return nextElementSiblingWithTagName(child, tag);
  }
  return child;
}

var getActivatedObject = function(e) {
  var obj;
  if (!e) {
    // early version of IE
    obj = window.event.srcElement;
  } else if (e.srcElement) {
    // IE 7 or later
    obj = e.srcElement;
  } else {
    // DOM Level 2 browser
    obj = e.target;
  }
  return obj;
}
